use std::collections::HashMap;

use super::SearchIndex;
use crate::util::*;
use minicbor::{decode, Decoder};

/*
{} = fixed length array
{
    String,             // filter name
    [
        {
            String,     // filter value
            [
                u32     // page number
                ...
            ]
        },
        ...
    ]
}
*/

impl SearchIndex {
    pub fn decode_filter_index_chunk(&mut self, filter_bytes: &[u8]) -> Result<(), decode::Error> {
        debug!({ format!("Decoding {:#?} filter index bytes", filter_bytes.len()) });
        let mut decoder = Decoder::new(filter_bytes);

        consume_fixed_arr!(decoder);

        debug!({ "Reading filter name" });
        let filter = consume_string!(decoder);

        debug!({ "Reading values array" });
        let values = consume_arr_len!(decoder);

        debug!({ format!("Reading {:#?} values", values) });
        let mut value_map = HashMap::new();
        for _ in 0..values {
            consume_fixed_arr!(decoder);
            let value = consume_string!(decoder);

            let pages = consume_arr_len!(decoder);
            let mut page_arr = Vec::with_capacity(pages as usize);
            for _ in 0..pages {
                page_arr.push(consume_num!(decoder));
            }

            value_map.insert(value, page_arr);
        }

        self.filters.insert(filter, value_map);

        debug!({ "Finished reading values" });

        Ok(())
    }

    // Used to parse one-off filters that were generated by the JS API, not the Rust CLI
    pub fn decode_synthetic_filter(&mut self, filter: &str) {
        let filters = filter.split("__PF_FILTER_DELIM__");

        for filter in filters {
            if let Some((filter, value)) = filter.split_once(':') {
                debug!({
                    format! {"Hardcoding index filter {}: {}", filter, value}
                });
                let all_pages = Vec::from_iter(0..self.pages.len() as u32);
                if let Some(filter_map) = self.filters.get_mut(filter) {
                    debug!({
                        format! {"Found a map for {}: {:#?}", filter, filter_map}
                    });
                    filter_map.insert(value.to_string(), all_pages);
                } else {
                    debug!({
                        format! {"No map found for {}, adding one.", filter}
                    });
                    let mut filter_map = HashMap::new();
                    filter_map.insert(value.to_string(), all_pages);
                    self.filters.insert(filter.to_string(), filter_map);
                }
            } else {
                debug!({
                    format! {"Bad filter (no `:`): {:?}", filter}
                })
            }
        }
    }
}
